// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Microsoft.AspNetCore.StaticWebAssets.Tasks;

internal sealed class ContentTypeProvider
{
    private static readonly Dictionary<string, ContentTypeMapping> _builtInMappings =
        new()
        {
            ["*.js"] = new ContentTypeMapping("text/javascript", null, "*.js", 1),
            ["*.css"] = new ContentTypeMapping("text/css", null, "*.css", 1),
            ["*.html"] = new ContentTypeMapping("text/html", null, "*.html", 1),
            ["*.json"] = new ContentTypeMapping("application/json", null, "*.json", 1),
            ["*.mjs"] = new ContentTypeMapping("text/javascript", null, "*.mjs", 1),
            ["*.xml"] = new ContentTypeMapping("text/xml", null, "*.xml", 1),
            ["*.htm"] = new ContentTypeMapping("text/html", null, "*.htm", 1),
            ["*.wasm"] = new ContentTypeMapping("application/wasm", null, "*.wasm", 1),
            ["*.txt"] = new ContentTypeMapping("text/plain", null, "*.txt", 1),
            ["*.dll"] = new ContentTypeMapping("application/octet-stream", null, "*.dll", 1),
            ["*.pdb"] = new ContentTypeMapping("application/octet-stream", null, "*.pdb", 1),
            ["*.dat"] = new ContentTypeMapping("application/octet-stream", null, "*.dat", 1),
            ["*.webmanifest"] = new ContentTypeMapping("application/manifest+json", null, "*.webmanifest", 1),
            ["*.jsx"] = new ContentTypeMapping("text/jscript", null, "*.jsx", 1),
            ["*.markdown"] = new ContentTypeMapping("text/markdown", null, "*.markdown", 1),
            ["*.gz"] = new ContentTypeMapping("application/x-gzip", null, "*.gz", 1),
            ["*.br"] = new ContentTypeMapping("application/octet-stream", null, "*.br", 1),
            ["*.md"] = new ContentTypeMapping("text/markdown", null, "*.md", 1),
            ["*.bmp"] = new ContentTypeMapping("image/bmp", null, "*.bmp", 1),
            ["*.jpeg"] = new ContentTypeMapping("image/jpeg", null, "*.jpeg", 1),
            ["*.jpg"] = new ContentTypeMapping("image/jpeg", null, "*.jpg", 1),
            ["*.gif"] = new ContentTypeMapping("image/gif", null, "*.gif", 1),
            ["*.svg"] = new ContentTypeMapping("image/svg+xml", null, "*.svg", 1),
            ["*.png"] = new ContentTypeMapping("image/png", null, "*.png", 1),
            ["*.webp"] = new ContentTypeMapping("image/webp", null, "*.webp", 1),
            ["*.otf"] = new ContentTypeMapping("font/otf", null, "*.otf", 1),
            ["*.woff2"] = new ContentTypeMapping("font/woff2", null, "*.woff2", 1),
            ["*.m4v"] = new ContentTypeMapping("video/mp4", null, "*.m4v", 1),
            ["*.mov"] = new ContentTypeMapping("video/quicktime", null, "*.mov", 1),
            ["*.movie"] = new ContentTypeMapping("video/x-sgi-movie", null, "*.movie", 1),
            ["*.mp2"] = new ContentTypeMapping("video/mpeg", null, "*.mp2", 1),
            ["*.mp4"] = new ContentTypeMapping("video/mp4", null, "*.mp4", 1),
            ["*.mp4v"] = new ContentTypeMapping("video/mp4", null, "*.mp4v", 1),
            ["*.mpa"] = new ContentTypeMapping("video/mpeg", null, "*.mpa", 1),
            ["*.mpe"] = new ContentTypeMapping("video/mpeg", null, "*.mpe", 1),
            ["*.mpeg"] = new ContentTypeMapping("video/mpeg", null, "*.mpeg", 1),
            ["*.mpg"] = new ContentTypeMapping("video/mpeg", null, "*.mpg", 1),
            ["*.mpv2"] = new ContentTypeMapping("video/mpeg", null, "*.mpv2", 1),
            ["*.nsc"] = new ContentTypeMapping("video/x-ms-asf", null, "*.nsc", 1),
            ["*.ogg"] = new ContentTypeMapping("video/ogg", null, "*.ogg", 1),
            ["*.ogv"] = new ContentTypeMapping("video/ogg", null, "*.ogv", 1),
            ["*.webm"] = new ContentTypeMapping("video/webm", null, "*.webm", 1),
            ["*.323"] = new ContentTypeMapping("text/h323", null, "*.323", 1),
            ["*.appcache"] = new ContentTypeMapping("text/cache-manifest", null, "*.appcache", 1),
            ["*.asm"] = new ContentTypeMapping("text/plain", null, "*.asm", 1),
            ["*.bas"] = new ContentTypeMapping("text/plain", null, "*.bas", 1),
            ["*.c"] = new ContentTypeMapping("text/plain", null, "*.c", 1),
            ["*.cnf"] = new ContentTypeMapping("text/plain", null, "*.cnf", 1),
            ["*.cpp"] = new ContentTypeMapping("text/plain", null, "*.cpp", 1),
            ["*.csv"] = new ContentTypeMapping("text/csv", null, "*.csv", 1),
            ["*.disco"] = new ContentTypeMapping("text/xml", null, "*.disco", 1),
            ["*.dlm"] = new ContentTypeMapping("text/dlm", null, "*.dlm", 1),
            ["*.dtd"] = new ContentTypeMapping("text/xml", null, "*.dtd", 1),
            ["*.etx"] = new ContentTypeMapping("text/x-setext", null, "*.etx", 1),
            ["*.h"] = new ContentTypeMapping("text/plain", null, "*.h", 1),
            ["*.hdml"] = new ContentTypeMapping("text/x-hdml", null, "*.hdml", 1),
            ["*.htc"] = new ContentTypeMapping("text/x-component", null, "*.htc", 1),
            ["*.htt"] = new ContentTypeMapping("text/webviewhtml", null, "*.htt", 1),
            ["*.hxt"] = new ContentTypeMapping("text/html", null, "*.hxt", 1),
            ["*.ical"] = new ContentTypeMapping("text/calendar", null, "*.ical", 1),
            ["*.icalendar"] = new ContentTypeMapping("text/calendar", null, "*.icalendar", 1),
            ["*.ics"] = new ContentTypeMapping("text/calendar", null, "*.ics", 1),
            ["*.ifb"] = new ContentTypeMapping("text/calendar", null, "*.ifb", 1),
            ["*.map"] = new ContentTypeMapping("text/plain", null, "*.map", 1),
            ["*.mno"] = new ContentTypeMapping("text/xml", null, "*.mno", 1),
            ["*.odc"] = new ContentTypeMapping("text/x-ms-odc", null, "*.odc", 1),
            ["*.rtx"] = new ContentTypeMapping("text/richtext", null, "*.rtx", 1),
            ["*.sct"] = new ContentTypeMapping("text/scriptlet", null, "*.sct", 1),
            ["*.sgml"] = new ContentTypeMapping("text/sgml", null, "*.sgml", 1),
            ["*.tsv"] = new ContentTypeMapping("text/tab-separated-values", null, "*.tsv", 1),
            ["*.uls"] = new ContentTypeMapping("text/iuls", null, "*.uls", 1),
            ["*.vbs"] = new ContentTypeMapping("text/vbscript", null, "*.vbs", 1),
            ["*.vcf"] = new ContentTypeMapping("text/x-vcard", null, "*.vcf", 1),
            ["*.vcs"] = new ContentTypeMapping("text/plain", null, "*.vcs", 1),
            ["*.vml"] = new ContentTypeMapping("text/xml", null, "*.vml", 1),
            ["*.wml"] = new ContentTypeMapping("text/vnd.wap.wml", null, "*.wml", 1),
            ["*.wmls"] = new ContentTypeMapping("text/vnd.wap.wmlscript", null, "*.wmls", 1),
            ["*.wsdl"] = new ContentTypeMapping("text/xml", null, "*.wsdl", 1),
            ["*.xdr"] = new ContentTypeMapping("text/plain", null, "*.xdr", 1),
            ["*.xsd"] = new ContentTypeMapping("text/xml", null, "*.xsd", 1),
            ["*.xsf"] = new ContentTypeMapping("text/xml", null, "*.xsf", 1),
            ["*.xsl"] = new ContentTypeMapping("text/xml", null, "*.xsl", 1),
            ["*.xslt"] = new ContentTypeMapping("text/xml", null, "*.xslt", 1),
            ["*.woff"] = new ContentTypeMapping("application/font-woff", null, "*.woff", 1),
            ["*.art"] = new ContentTypeMapping("image/x-jg", null, "*.art", 1),
            ["*.cmx"] = new ContentTypeMapping("image/x-cmx", null, "*.cmx", 1),
            ["*.cod"] = new ContentTypeMapping("image/cis-cod", null, "*.cod", 1),
            ["*.dib"] = new ContentTypeMapping("image/bmp", null, "*.dib", 1),
            ["*.ico"] = new ContentTypeMapping("image/x-icon", null, "*.ico", 1),
            ["*.ief"] = new ContentTypeMapping("image/ief", null, "*.ief", 1),
            ["*.jfif"] = new ContentTypeMapping("image/pjpeg", null, "*.jfif", 1),
            ["*.jpe"] = new ContentTypeMapping("image/jpeg", null, "*.jpe", 1),
            ["*.pbm"] = new ContentTypeMapping("image/x-portable-bitmap", null, "*.pbm", 1),
            ["*.pgm"] = new ContentTypeMapping("image/x-portable-graymap", null, "*.pgm", 1),
            ["*.pnm"] = new ContentTypeMapping("image/x-portable-anymap", null, "*.pnm", 1),
            ["*.pnz"] = new ContentTypeMapping("image/png", null, "*.pnz", 1),
            ["*.ppm"] = new ContentTypeMapping("image/x-portable-pixmap", null, "*.ppm", 1),
            ["*.ras"] = new ContentTypeMapping("image/x-cmu-raster", null, "*.ras", 1),
            ["*.rf"] = new ContentTypeMapping("image/vnd.rn-realflash", null, "*.rf", 1),
            ["*.rgb"] = new ContentTypeMapping("image/x-rgb", null, "*.rgb", 1),
            ["*.svgz"] = new ContentTypeMapping("image/svg+xml", null, "*.svgz", 1),
            ["*.tif"] = new ContentTypeMapping("image/tiff", null, "*.tif", 1),
            ["*.tiff"] = new ContentTypeMapping("image/tiff", null, "*.tiff", 1),
            ["*.wbmp"] = new ContentTypeMapping("image/vnd.wap.wbmp", null, "*.wbmp", 1),
            ["*.xbm"] = new ContentTypeMapping("image/x-xbitmap", null, "*.xbm", 1),
            ["*.xpm"] = new ContentTypeMapping("image/x-xpixmap", null, "*.xpm", 1),
            ["*.xwd"] = new ContentTypeMapping("image/x-xwindowdump", null, "*.xwd", 1),
            ["*.3g2"] = new ContentTypeMapping("video/3gpp2", null, "*.3g2", 1),
            ["*.3gp2"] = new ContentTypeMapping("video/3gpp2", null, "*.3gp2", 1),
            ["*.3gp"] = new ContentTypeMapping("video/3gpp", null, "*.3gp", 1),
            ["*.3gpp"] = new ContentTypeMapping("video/3gpp", null, "*.3gpp", 1),
            ["*.asf"] = new ContentTypeMapping("video/x-ms-asf", null, "*.asf", 1),
            ["*.asr"] = new ContentTypeMapping("video/x-ms-asf", null, "*.asr", 1),
            ["*.asx"] = new ContentTypeMapping("video/x-ms-asf", null, "*.asx", 1),
            ["*.avi"] = new ContentTypeMapping("video/x-msvideo", null, "*.avi", 1),
            ["*.dvr"] = new ContentTypeMapping("video/x-ms-dvr", null, "*.dvr", 1),
            ["*.flv"] = new ContentTypeMapping("video/x-flv", null, "*.flv", 1),
            ["*.IVF"] = new ContentTypeMapping("video/x-ivf", null, "*.IVF", 1),
            ["*.lsf"] = new ContentTypeMapping("video/x-la-asf", null, "*.lsf", 1),
            ["*.lsx"] = new ContentTypeMapping("video/x-la-asf", null, "*.lsx", 1),
            ["*.m1v"] = new ContentTypeMapping("video/mpeg", null, "*.m1v", 1),
            ["*.m2ts"] = new ContentTypeMapping("video/vnd.dlna.mpeg-tts", null, "*.m2ts", 1),
            ["*.qt"] = new ContentTypeMapping("video/quicktime", null, "*.qt", 1),
            ["*.ts"] = new ContentTypeMapping("video/vnd.dlna.mpeg-tts", null, "*.ts", 1),
            ["*.tts"] = new ContentTypeMapping("video/vnd.dlna.mpeg-tts", null, "*.tts", 1),
            ["*.wm"] = new ContentTypeMapping("video/x-ms-wm", null, "*.wm", 1),
            ["*.wmp"] = new ContentTypeMapping("video/x-ms-wmp", null, "*.wmp", 1),
            ["*.wmv"] = new ContentTypeMapping("video/x-ms-wmv", null, "*.wmv", 1),
            ["*.wmx"] = new ContentTypeMapping("video/x-ms-wmx", null, "*.wmx", 1),
            ["*.wtv"] = new ContentTypeMapping("video/x-ms-wtv", null, "*.wtv", 1),
            ["*.wvx"] = new ContentTypeMapping("video/x-ms-wvx", null, "*.wvx", 1),
            ["*.aac"] = new ContentTypeMapping("audio/aac", null, "*.aac", 1),
            ["*.adt"] = new ContentTypeMapping("audio/vnd.dlna.adts", null, "*.adt", 1),
            ["*.adts"] = new ContentTypeMapping("audio/vnd.dlna.adts", null, "*.adts", 1),
            ["*.aif"] = new ContentTypeMapping("audio/x-aiff", null, "*.aif", 1),
            ["*.aifc"] = new ContentTypeMapping("audio/aiff", null, "*.aifc", 1),
            ["*.aiff"] = new ContentTypeMapping("audio/aiff", null, "*.aiff", 1),
            ["*.au"] = new ContentTypeMapping("audio/basic", null, "*.au", 1),
            ["*.m3u"] = new ContentTypeMapping("audio/x-mpegurl", null, "*.m3u", 1),
            ["*.m4a"] = new ContentTypeMapping("audio/mp4", null, "*.m4a", 1),
            ["*.mid"] = new ContentTypeMapping("audio/mid", null, "*.mid", 1),
            ["*.midi"] = new ContentTypeMapping("audio/mid", null, "*.midi", 1),
            ["*.mp3"] = new ContentTypeMapping("audio/mpeg", null, "*.mp3", 1),
            ["*.oga"] = new ContentTypeMapping("audio/ogg", null, "*.oga", 1),
            ["*.ra"] = new ContentTypeMapping("audio/x-pn-realaudio", null, "*.ra", 1),
            ["*.ram"] = new ContentTypeMapping("audio/x-pn-realaudio", null, "*.ram", 1),
            ["*.rmi"] = new ContentTypeMapping("audio/mid", null, "*.rmi", 1),
            ["*.rpm"] = new ContentTypeMapping("audio/x-pn-realaudio-plugin", null, "*.rpm", 1),
            ["*.smd"] = new ContentTypeMapping("audio/x-smd", null, "*.smd", 1),
            ["*.smx"] = new ContentTypeMapping("audio/x-smd", null, "*.smx", 1),
            ["*.smz"] = new ContentTypeMapping("audio/x-smd", null, "*.smz", 1),
            ["*.snd"] = new ContentTypeMapping("audio/basic", null, "*.snd", 1),
            ["*.spx"] = new ContentTypeMapping("audio/ogg", null, "*.spx", 1),
            ["*.wav"] = new ContentTypeMapping("audio/wav", null, "*.wav", 1),
            ["*.wax"] = new ContentTypeMapping("audio/x-ms-wax", null, "*.wax", 1),
            ["*.wma"] = new ContentTypeMapping("audio/x-ms-wma", null, "*.wma", 1),
            ["*.accdb"] = new ContentTypeMapping("application/msaccess", null, "*.accdb", 1),
            ["*.accde"] = new ContentTypeMapping("application/msaccess", null, "*.accde", 1),
            ["*.accdt"] = new ContentTypeMapping("application/msaccess", null, "*.accdt", 1),
            ["*.acx"] = new ContentTypeMapping("application/internet-property-stream", null, "*.acx", 1),
            ["*.ai"] = new ContentTypeMapping("application/postscript", null, "*.ai", 1),
            ["*.application"] = new ContentTypeMapping("application/x-ms-application", null, "*.application", 1),
            ["*.atom"] = new ContentTypeMapping("application/atom+xml", null, "*.atom", 1),
            ["*.axs"] = new ContentTypeMapping("application/olescript", null, "*.axs", 1),
            ["*.bcpio"] = new ContentTypeMapping("application/x-bcpio", null, "*.bcpio", 1),
            ["*.cab"] = new ContentTypeMapping("application/vnd.ms-cab-compressed", null, "*.cab", 1),
            ["*.calx"] = new ContentTypeMapping("application/vnd.ms-office.calx", null, "*.calx", 1),
            ["*.cat"] = new ContentTypeMapping("application/vnd.ms-pki.seccat", null, "*.cat", 1),
            ["*.cdf"] = new ContentTypeMapping("application/x-cdf", null, "*.cdf", 1),
            ["*.class"] = new ContentTypeMapping("application/x-java-applet", null, "*.class", 1),
            ["*.clp"] = new ContentTypeMapping("application/x-msclip", null, "*.clp", 1),
            ["*.cpio"] = new ContentTypeMapping("application/x-cpio", null, "*.cpio", 1),
            ["*.crd"] = new ContentTypeMapping("application/x-mscardfile", null, "*.crd", 1),
            ["*.crl"] = new ContentTypeMapping("application/pkix-crl", null, "*.crl", 1),
            ["*.crt"] = new ContentTypeMapping("application/x-x509-ca-cert", null, "*.crt", 1),
            ["*.csh"] = new ContentTypeMapping("application/x-csh", null, "*.csh", 1),
            ["*.dcr"] = new ContentTypeMapping("application/x-director", null, "*.dcr", 1),
            ["*.der"] = new ContentTypeMapping("application/x-x509-ca-cert", null, "*.der", 1),
            ["*.dir"] = new ContentTypeMapping("application/x-director", null, "*.dir", 1),
            ["*.doc"] = new ContentTypeMapping("application/msword", null, "*.doc", 1),
            ["*.docm"] = new ContentTypeMapping("application/vnd.ms-word.document.macroEnabled.12", null, "*.docm", 1),
            ["*.docx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.wordprocessingml.document", null, "*.docx", 1),
            ["*.dot"] = new ContentTypeMapping("application/msword", null, "*.dot", 1),
            ["*.dotm"] = new ContentTypeMapping("application/vnd.ms-word.template.macroEnabled.12", null, "*.dotm", 1),
            ["*.dotx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.wordprocessingml.template", null, "*.dotx", 1),
            ["*.dvi"] = new ContentTypeMapping("application/x-dvi", null, "*.dvi", 1),
            ["*.dwf"] = new ContentTypeMapping("drawing/x-dwf", null, "*.dwf", 1),
            ["*.dxr"] = new ContentTypeMapping("application/x-director", null, "*.dxr", 1),
            ["*.eml"] = new ContentTypeMapping("message/rfc822", null, "*.eml", 1),
            ["*.eot"] = new ContentTypeMapping("application/vnd.ms-fontobject", null, "*.eot", 1),
            ["*.eps"] = new ContentTypeMapping("application/postscript", null, "*.eps", 1),
            ["*.evy"] = new ContentTypeMapping("application/envoy", null, "*.evy", 1),
            ["*.exe"] = new ContentTypeMapping("application/vnd.microsoft.portable-executable", null, "*.exe", 1),
            ["*.fdf"] = new ContentTypeMapping("application/vnd.fdf", null, "*.fdf", 1),
            ["*.fif"] = new ContentTypeMapping("application/fractals", null, "*.fif", 1),
            ["*.flr"] = new ContentTypeMapping("x-world/x-vrml", null, "*.flr", 1),
            ["*.gtar"] = new ContentTypeMapping("application/x-gtar", null, "*.gtar", 1),
            ["*.hdf"] = new ContentTypeMapping("application/x-hdf", null, "*.hdf", 1),
            ["*.hhc"] = new ContentTypeMapping("application/x-oleobject", null, "*.hhc", 1),
            ["*.hlp"] = new ContentTypeMapping("application/winhlp", null, "*.hlp", 1),
            ["*.hqx"] = new ContentTypeMapping("application/mac-binhex40", null, "*.hqx", 1),
            ["*.hta"] = new ContentTypeMapping("application/hta", null, "*.hta", 1),
            ["*.iii"] = new ContentTypeMapping("application/x-iphone", null, "*.iii", 1),
            ["*.ins"] = new ContentTypeMapping("application/x-internet-signup", null, "*.ins", 1),
            ["*.isp"] = new ContentTypeMapping("application/x-internet-signup", null, "*.isp", 1),
            ["*.jar"] = new ContentTypeMapping("application/java-archive", null, "*.jar", 1),
            ["*.jck"] = new ContentTypeMapping("application/liquidmotion", null, "*.jck", 1),
            ["*.jcz"] = new ContentTypeMapping("application/liquidmotion", null, "*.jcz", 1),
            ["*.latex"] = new ContentTypeMapping("application/x-latex", null, "*.latex", 1),
            ["*.lit"] = new ContentTypeMapping("application/x-ms-reader", null, "*.lit", 1),
            ["*.m13"] = new ContentTypeMapping("application/x-msmediaview", null, "*.m13", 1),
            ["*.m14"] = new ContentTypeMapping("application/x-msmediaview", null, "*.m14", 1),
            ["*.man"] = new ContentTypeMapping("application/x-troff-man", null, "*.man", 1),
            ["*.manifest"] = new ContentTypeMapping("application/x-ms-manifest", null, "*.manifest", 1),
            ["*.mdb"] = new ContentTypeMapping("application/x-msaccess", null, "*.mdb", 1),
            ["*.me"] = new ContentTypeMapping("application/x-troff-me", null, "*.me", 1),
            ["*.mht"] = new ContentTypeMapping("message/rfc822", null, "*.mht", 1),
            ["*.mhtml"] = new ContentTypeMapping("message/rfc822", null, "*.mhtml", 1),
            ["*.mmf"] = new ContentTypeMapping("application/x-smaf", null, "*.mmf", 1),
            ["*.mny"] = new ContentTypeMapping("application/x-msmoney", null, "*.mny", 1),
            ["*.mpp"] = new ContentTypeMapping("application/vnd.ms-project", null, "*.mpp", 1),
            ["*.ms"] = new ContentTypeMapping("application/x-troff-ms", null, "*.ms", 1),
            ["*.mvb"] = new ContentTypeMapping("application/x-msmediaview", null, "*.mvb", 1),
            ["*.mvc"] = new ContentTypeMapping("application/x-miva-compiled", null, "*.mvc", 1),
            ["*.nc"] = new ContentTypeMapping("application/x-netcdf", null, "*.nc", 1),
            ["*.nws"] = new ContentTypeMapping("message/rfc822", null, "*.nws", 1),
            ["*.oda"] = new ContentTypeMapping("application/oda", null, "*.oda", 1),
            ["*.ods"] = new ContentTypeMapping("application/oleobject", null, "*.ods", 1),
            ["*.ogx"] = new ContentTypeMapping("application/ogg", null, "*.ogx", 1),
            ["*.one"] = new ContentTypeMapping("application/onenote", null, "*.one", 1),
            ["*.onea"] = new ContentTypeMapping("application/onenote", null, "*.onea", 1),
            ["*.onetoc"] = new ContentTypeMapping("application/onenote", null, "*.onetoc", 1),
            ["*.onetoc2"] = new ContentTypeMapping("application/onenote", null, "*.onetoc2", 1),
            ["*.onetmp"] = new ContentTypeMapping("application/onenote", null, "*.onetmp", 1),
            ["*.onepkg"] = new ContentTypeMapping("application/onenote", null, "*.onepkg", 1),
            ["*.osdx"] = new ContentTypeMapping("application/opensearchdescription+xml", null, "*.osdx", 1),
            ["*.p10"] = new ContentTypeMapping("application/pkcs10", null, "*.p10", 1),
            ["*.p12"] = new ContentTypeMapping("application/x-pkcs12", null, "*.p12", 1),
            ["*.p7b"] = new ContentTypeMapping("application/x-pkcs7-certificates", null, "*.p7b", 1),
            ["*.p7c"] = new ContentTypeMapping("application/pkcs7-mime", null, "*.p7c", 1),
            ["*.p7m"] = new ContentTypeMapping("application/pkcs7-mime", null, "*.p7m", 1),
            ["*.p7r"] = new ContentTypeMapping("application/x-pkcs7-certreqresp", null, "*.p7r", 1),
            ["*.p7s"] = new ContentTypeMapping("application/pkcs7-signature", null, "*.p7s", 1),
            ["*.pdf"] = new ContentTypeMapping("application/pdf", null, "*.pdf", 1),
            ["*.pfx"] = new ContentTypeMapping("application/x-pkcs12", null, "*.pfx", 1),
            ["*.pko"] = new ContentTypeMapping("application/vnd.ms-pki.pko", null, "*.pko", 1),
            ["*.pma"] = new ContentTypeMapping("application/x-perfmon", null, "*.pma", 1),
            ["*.pmc"] = new ContentTypeMapping("application/x-perfmon", null, "*.pmc", 1),
            ["*.pml"] = new ContentTypeMapping("application/x-perfmon", null, "*.pml", 1),
            ["*.pmr"] = new ContentTypeMapping("application/x-perfmon", null, "*.pmr", 1),
            ["*.pmw"] = new ContentTypeMapping("application/x-perfmon", null, "*.pmw", 1),
            ["*.pot"] = new ContentTypeMapping("application/vnd.ms-powerpoint", null, "*.pot", 1),
            ["*.potm"] = new ContentTypeMapping("application/vnd.ms-powerpoint.template.macroEnabled.12", null, "*.potm", 1),
            ["*.potx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.presentationml.template", null, "*.potx", 1),
            ["*.ppam"] = new ContentTypeMapping("application/vnd.ms-powerpoint.addin.macroEnabled.12", null, "*.ppam", 1),
            ["*.pps"] = new ContentTypeMapping("application/vnd.ms-powerpoint", null, "*.pps", 1),
            ["*.ppsm"] = new ContentTypeMapping("application/vnd.ms-powerpoint.slideshow.macroEnabled.12", null, "*.ppsm", 1),
            ["*.ppsx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.presentationml.slideshow", null, "*.ppsx", 1),
            ["*.ppt"] = new ContentTypeMapping("application/vnd.ms-powerpoint", null, "*.ppt", 1),
            ["*.pptm"] = new ContentTypeMapping("application/vnd.ms-powerpoint.presentation.macroEnabled.12", null, "*.pptm", 1),
            ["*.pptx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.presentationml.presentation", null, "*.pptx", 1),
            ["*.prf"] = new ContentTypeMapping("application/pics-rules", null, "*.prf", 1),
            ["*.ps"] = new ContentTypeMapping("application/postscript", null, "*.ps", 1),
            ["*.pub"] = new ContentTypeMapping("application/x-mspublisher", null, "*.pub", 1),
            ["*.qtl"] = new ContentTypeMapping("application/x-quicktimeplayer", null, "*.qtl", 1),
            ["*.rm"] = new ContentTypeMapping("application/vnd.rn-realmedia", null, "*.rm", 1),
            ["*.roff"] = new ContentTypeMapping("application/x-troff", null, "*.roff", 1),
            ["*.rtf"] = new ContentTypeMapping("application/rtf", null, "*.rtf", 1),
            ["*.scd"] = new ContentTypeMapping("application/x-msschedule", null, "*.scd", 1),
            ["*.setpay"] = new ContentTypeMapping("application/set-payment-initiation", null, "*.setpay", 1),
            ["*.setreg"] = new ContentTypeMapping("application/set-registration-initiation", null, "*.setreg", 1),
            ["*.sh"] = new ContentTypeMapping("application/x-sh", null, "*.sh", 1),
            ["*.shar"] = new ContentTypeMapping("application/x-shar", null, "*.shar", 1),
            ["*.sit"] = new ContentTypeMapping("application/x-stuffit", null, "*.sit", 1),
            ["*.sldm"] = new ContentTypeMapping("application/vnd.ms-powerpoint.slide.macroEnabled.12", null, "*.sldm", 1),
            ["*.sldx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.presentationml.slide", null, "*.sldx", 1),
            ["*.spc"] = new ContentTypeMapping("application/x-pkcs7-certificates", null, "*.spc", 1),
            ["*.spl"] = new ContentTypeMapping("application/futuresplash", null, "*.spl", 1),
            ["*.src"] = new ContentTypeMapping("application/x-wais-source", null, "*.src", 1),
            ["*.ssm"] = new ContentTypeMapping("application/streamingmedia", null, "*.ssm", 1),
            ["*.sst"] = new ContentTypeMapping("application/vnd.ms-pki.certstore", null, "*.sst", 1),
            ["*.stl"] = new ContentTypeMapping("application/vnd.ms-pki.stl", null, "*.stl", 1),
            ["*.sv4cpio"] = new ContentTypeMapping("application/x-sv4cpio", null, "*.sv4cpio", 1),
            ["*.sv4crc"] = new ContentTypeMapping("application/x-sv4crc", null, "*.sv4crc", 1),
            ["*.swf"] = new ContentTypeMapping("application/x-shockwave-flash", null, "*.swf", 1),
            ["*.t"] = new ContentTypeMapping("application/x-troff", null, "*.t", 1),
            ["*.tar"] = new ContentTypeMapping("application/x-tar", null, "*.tar", 1),
            ["*.tcl"] = new ContentTypeMapping("application/x-tcl", null, "*.tcl", 1),
            ["*.tex"] = new ContentTypeMapping("application/x-tex", null, "*.tex", 1),
            ["*.texi"] = new ContentTypeMapping("application/x-texinfo", null, "*.texi", 1),
            ["*.texinfo"] = new ContentTypeMapping("application/x-texinfo", null, "*.texinfo", 1),
            ["*.tgz"] = new ContentTypeMapping("application/x-compressed", null, "*.tgz", 1),
            ["*.thmx"] = new ContentTypeMapping("application/vnd.ms-officetheme", null, "*.thmx", 1),
            ["*.tr"] = new ContentTypeMapping("application/x-troff", null, "*.tr", 1),
            ["*.trm"] = new ContentTypeMapping("application/x-msterminal", null, "*.trm", 1),
            ["*.ttc"] = new ContentTypeMapping("application/x-font-ttf", null, "*.ttc", 1),
            ["*.ttf"] = new ContentTypeMapping("application/x-font-ttf", null, "*.ttf", 1),
            ["*.ustar"] = new ContentTypeMapping("application/x-ustar", null, "*.ustar", 1),
            ["*.vdx"] = new ContentTypeMapping("application/vnd.ms-visio.viewer", null, "*.vdx", 1),
            ["*.vsd"] = new ContentTypeMapping("application/vnd.visio", null, "*.vsd", 1),
            ["*.vss"] = new ContentTypeMapping("application/vnd.visio", null, "*.vss", 1),
            ["*.vst"] = new ContentTypeMapping("application/vnd.visio", null, "*.vst", 1),
            ["*.vsto"] = new ContentTypeMapping("application/x-ms-vsto", null, "*.vsto", 1),
            ["*.vsw"] = new ContentTypeMapping("application/vnd.visio", null, "*.vsw", 1),
            ["*.vsx"] = new ContentTypeMapping("application/vnd.visio", null, "*.vsx", 1),
            ["*.vtx"] = new ContentTypeMapping("application/vnd.visio", null, "*.vtx", 1),
            ["*.wcm"] = new ContentTypeMapping("application/vnd.ms-works", null, "*.wcm", 1),
            ["*.wdb"] = new ContentTypeMapping("application/vnd.ms-works", null, "*.wdb", 1),
            ["*.wks"] = new ContentTypeMapping("application/vnd.ms-works", null, "*.wks", 1),
            ["*.wmd"] = new ContentTypeMapping("application/x-ms-wmd", null, "*.wmd", 1),
            ["*.wmf"] = new ContentTypeMapping("application/x-msmetafile", null, "*.wmf", 1),
            ["*.wmlc"] = new ContentTypeMapping("application/vnd.wap.wmlc", null, "*.wmlc", 1),
            ["*.wmlsc"] = new ContentTypeMapping("application/vnd.wap.wmlscriptc", null, "*.wmlsc", 1),
            ["*.wmz"] = new ContentTypeMapping("application/x-ms-wmz", null, "*.wmz", 1),
            ["*.wps"] = new ContentTypeMapping("application/vnd.ms-works", null, "*.wps", 1),
            ["*.wri"] = new ContentTypeMapping("application/x-mswrite", null, "*.wri", 1),
            ["*.wrl"] = new ContentTypeMapping("x-world/x-vrml", null, "*.wrl", 1),
            ["*.wrz"] = new ContentTypeMapping("x-world/x-vrml", null, "*.wrz", 1),
            ["*.x"] = new ContentTypeMapping("application/directx", null, "*.x", 1),
            ["*.xaf"] = new ContentTypeMapping("x-world/x-vrml", null, "*.xaf", 1),
            ["*.xaml"] = new ContentTypeMapping("application/xaml+xml", null, "*.xaml", 1),
            ["*.xap"] = new ContentTypeMapping("application/x-silverlight-app", null, "*.xap", 1),
            ["*.xbap"] = new ContentTypeMapping("application/x-ms-xbap", null, "*.xbap", 1),
            ["*.xht"] = new ContentTypeMapping("application/xhtml+xml", null, "*.xht", 1),
            ["*.xhtml"] = new ContentTypeMapping("application/xhtml+xml", null, "*.xhtml", 1),
            ["*.xla"] = new ContentTypeMapping("application/vnd.ms-excel", null, "*.xla", 1),
            ["*.xlam"] = new ContentTypeMapping("application/vnd.ms-excel.addin.macroEnabled.12", null, "*.xlam", 1),
            ["*.xlc"] = new ContentTypeMapping("application/vnd.ms-excel", null, "*.xlc", 1),
            ["*.xlm"] = new ContentTypeMapping("application/vnd.ms-excel", null, "*.xlm", 1),
            ["*.xls"] = new ContentTypeMapping("application/vnd.ms-excel", null, "*.xls", 1),
            ["*.xlsb"] = new ContentTypeMapping("application/vnd.ms-excel.sheet.binary.macroEnabled.12", null, "*.xlsb", 1),
            ["*.xlsm"] = new ContentTypeMapping("application/vnd.ms-excel.sheet.macroEnabled.12", null, "*.xlsm", 1),
            ["*.xlsx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", null, "*.xlsx", 1),
            ["*.xlt"] = new ContentTypeMapping("application/vnd.ms-excel", null, "*.xlt", 1),
            ["*.xltm"] = new ContentTypeMapping("application/vnd.ms-excel.template.macroEnabled.12", null, "*.xltm", 1),
            ["*.xltx"] = new ContentTypeMapping("application/vnd.openxmlformats-officedocument.spreadsheetml.template", null, "*.xltx", 1),
            ["*.xlw"] = new ContentTypeMapping("application/vnd.ms-excel", null, "*.xlw", 1),
            ["*.xof"] = new ContentTypeMapping("x-world/x-vrml", null, "*.xof", 1),
            ["*.xps"] = new ContentTypeMapping("application/vnd.ms-xpsdocument", null, "*.xps", 1),
            ["*.z"] = new ContentTypeMapping("application/x-compress", null, "*.z", 1),
            ["*.zip"] = new ContentTypeMapping("application/x-zip-compressed", null, "*.zip", 1),
            ["*.aaf"] = new ContentTypeMapping("application/octet-stream", null, "*.aaf", 1),
            ["*.aca"] = new ContentTypeMapping("application/octet-stream", null, "*.aca", 1),
            ["*.afm"] = new ContentTypeMapping("application/octet-stream", null, "*.afm", 1),
            ["*.asd"] = new ContentTypeMapping("application/octet-stream", null, "*.asd", 1),
            ["*.asi"] = new ContentTypeMapping("application/octet-stream", null, "*.asi", 1),
            ["*.bin"] = new ContentTypeMapping("application/octet-stream", null, "*.bin", 1),
            ["*.chm"] = new ContentTypeMapping("application/octet-stream", null, "*.chm", 1),
            ["*.cur"] = new ContentTypeMapping("application/octet-stream", null, "*.cur", 1),
            ["*.deploy"] = new ContentTypeMapping("application/octet-stream", null, "*.deploy", 1),
            ["*.dsp"] = new ContentTypeMapping("application/octet-stream", null, "*.dsp", 1),
            ["*.dwp"] = new ContentTypeMapping("application/octet-stream", null, "*.dwp", 1),
            ["*.emz"] = new ContentTypeMapping("application/octet-stream", null, "*.emz", 1),
            ["*.fla"] = new ContentTypeMapping("application/octet-stream", null, "*.fla", 1),
            ["*.hhk"] = new ContentTypeMapping("application/octet-stream", null, "*.hhk", 1),
            ["*.hhp"] = new ContentTypeMapping("application/octet-stream", null, "*.hhp", 1),
            ["*.inf"] = new ContentTypeMapping("application/octet-stream", null, "*.inf", 1),
            ["*.java"] = new ContentTypeMapping("application/octet-stream", null, "*.java", 1),
            ["*.jpb"] = new ContentTypeMapping("application/octet-stream", null, "*.jpb", 1),
            ["*.lpk"] = new ContentTypeMapping("application/octet-stream", null, "*.lpk", 1),
            ["*.lzh"] = new ContentTypeMapping("application/octet-stream", null, "*.lzh", 1),
            ["*.mdp"] = new ContentTypeMapping("application/octet-stream", null, "*.mdp", 1),
            ["*.mix"] = new ContentTypeMapping("application/octet-stream", null, "*.mix", 1),
            ["*.msi"] = new ContentTypeMapping("application/octet-stream", null, "*.msi", 1),
            ["*.mso"] = new ContentTypeMapping("application/octet-stream", null, "*.mso", 1),
            ["*.ocx"] = new ContentTypeMapping("application/octet-stream", null, "*.ocx", 1),
            ["*.pcx"] = new ContentTypeMapping("application/octet-stream", null, "*.pcx", 1),
            ["*.pcz"] = new ContentTypeMapping("application/octet-stream", null, "*.pcz", 1),
            ["*.pfb"] = new ContentTypeMapping("application/octet-stream", null, "*.pfb", 1),
            ["*.pfm"] = new ContentTypeMapping("application/octet-stream", null, "*.pfm", 1),
            ["*.prm"] = new ContentTypeMapping("application/octet-stream", null, "*.prm", 1),
            ["*.prx"] = new ContentTypeMapping("application/octet-stream", null, "*.prx", 1),
            ["*.psd"] = new ContentTypeMapping("application/octet-stream", null, "*.psd", 1),
            ["*.psm"] = new ContentTypeMapping("application/octet-stream", null, "*.psm", 1),
            ["*.psp"] = new ContentTypeMapping("application/octet-stream", null, "*.psp", 1),
            ["*.qxd"] = new ContentTypeMapping("application/octet-stream", null, "*.qxd", 1),
            ["*.rar"] = new ContentTypeMapping("application/octet-stream", null, "*.rar", 1),
            ["*.sea"] = new ContentTypeMapping("application/octet-stream", null, "*.sea", 1),
            ["*.smi"] = new ContentTypeMapping("application/octet-stream", null, "*.smi", 1),
            ["*.snp"] = new ContentTypeMapping("application/octet-stream", null, "*.snp", 1),
            ["*.thn"] = new ContentTypeMapping("application/octet-stream", null, "*.thn", 1),
            ["*.toc"] = new ContentTypeMapping("application/octet-stream", null, "*.toc", 1),
            ["*.u32"] = new ContentTypeMapping("application/octet-stream", null, "*.u32", 1),
            ["*.xsn"] = new ContentTypeMapping("application/octet-stream", null, "*.xsn", 1),
            ["*.xtp"] = new ContentTypeMapping("application/octet-stream", null, "*.xtp", 1),
        };

    private readonly StaticWebAssetGlobMatcher _matcher;

    private readonly Dictionary<string, ContentTypeMapping> _customMappings;

    public ContentTypeProvider(ContentTypeMapping[] customMappings)
    {
        _customMappings ??= [];
        foreach (var mapping in customMappings)
        {
            _customMappings[mapping.Pattern] = mapping;
        }

        _matcher = new StaticWebAssetGlobMatcherBuilder()
            .AddIncludePatternsList(_builtInMappings.Keys)
            .AddIncludePatternsList(_customMappings.Keys)
            .Build();
    }

    // First we strip any compressed extension (e.g. .gz, .br) from the file name
    // and then we try to match the file name with the existing mappings.
    // If we don't find a match, we fallback to trying the entire file name.
    internal ContentTypeMapping ResolveContentTypeMapping(StaticWebAssetGlobMatcher.MatchContext context, TaskLoggingHelper log)
    {
#if NET9_0_OR_GREATER
        var relativePath = context.Path;
        var fileNameSpan = Path.GetFileName(context.Path);
        var fileName = relativePath[(relativePath.Length - fileNameSpan.Length)..];
#else
        var relativePath = context.PathString;
        var fileName = Path.GetFileName(relativePath);
#endif
        var fileNameNoCompressionExt = ResolvePathWithoutCompressedExtension(fileName, out var hasCompressedExtension);

        context.SetPathAndReinitialize(fileNameNoCompressionExt);
        if (TryGetMapping(context, log, relativePath, out var mapping))
        {
            return mapping;
        }
        else if (hasCompressedExtension)
        {
            context.SetPathAndReinitialize(fileName);
            if (hasCompressedExtension && TryGetMapping(context, log, relativePath, out mapping))
            {
                return mapping;
            }
        }

        return default;
    }

#if NET9_0_OR_GREATER
    private bool TryGetMapping(StaticWebAssetGlobMatcher.MatchContext context, TaskLoggingHelper log, ReadOnlySpan<char> relativePath, out ContentTypeMapping mapping)
#else
    private bool TryGetMapping(StaticWebAssetGlobMatcher.MatchContext context, TaskLoggingHelper log, string relativePath, out ContentTypeMapping mapping)
#endif
    {
        var match = _matcher.Match(context);
        if (match.IsMatch)
        {
            if (_customMappings.TryGetValue(match.Pattern, out mapping) || _builtInMappings.TryGetValue(match.Pattern, out mapping))
            {
                log.LogMessage(MessageImportance.Low, $"Matched {relativePath} to {mapping.MimeType} using pattern {match.Pattern}");
                return true;
            }
            else
            {
                throw new InvalidOperationException("Matched pattern but no mapping found.");
            }
        }

        mapping = default;
        return false;
    }

#if NET9_0_OR_GREATER
    private static ReadOnlySpan<char> ResolvePathWithoutCompressedExtension(ReadOnlySpan<char> fileName, out bool hasCompressedExtension)
#else
    private static string ResolvePathWithoutCompressedExtension(string fileName, out bool hasCompressedExtension)
#endif
    {
        var extension = Path.GetExtension(fileName);
        hasCompressedExtension = extension.Equals(".gz", StringComparison.OrdinalIgnoreCase) || extension.Equals(".br", StringComparison.OrdinalIgnoreCase);
        if (hasCompressedExtension)
        {
            var fileNameNoExtension = Path.GetFileNameWithoutExtension(fileName);
            if (!Path.GetExtension(fileNameNoExtension).Equals("", StringComparison.Ordinal))
            {
#if NET9_0_OR_GREATER
                return fileName[..fileNameNoExtension.Length];
#else
                return fileName.Substring(0, fileNameNoExtension.Length);
#endif
            }
        }

        return fileName;
    }
}
